#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "fdk-aac/aacenc_lib.h"
#include "maz/assert.h"

int dlvl = DINF;

int main(int argc, char *argv[])
{
    int i = 0;
    int ret = -1;
    int ifd = 0;
    int ofd = -1;

    /* AAC 编码库配置 */
    int channels = 1;
    int aot = 2;
    int eld_sbr = 0;
    int sample_rate = 8000;
    int vbr = 0;
    int bitrate = 64000;
    int afterburner = 1;
    HANDLE_AACENCODER handle = NULL;
    CHANNEL_MODE mode = MODE_1;
    AACENC_InfoStruct info = { 0 };

    if (argc != 3)
    {
        dlog(DERR, "usage: %s <iname> <oname>\n", argv[0]);
        return -1;
    }

    ifd = open(argv[1], O_RDWR | O_CREAT, 0777);
    MAZASSERT_RETVAL(ifd < 0, -1, "create pcm file failed");

    ofd = open(argv[2], O_RDWR | O_CREAT, 0777);
    MAZASSERT_RETVAL(ofd < 0, -1, "create aenc file failed");

    ret = aacEncOpen(&handle, 0, channels);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncOpen");

    ret = aacEncoder_SetParam(handle, AACENC_AOT, aot);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_AOT");

    if (aot == 39 && eld_sbr)
    {
        ret = aacEncoder_SetParam(handle, AACENC_SBR_MODE, 1);
        MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_SBR_MODE");
    }

    ret = aacEncoder_SetParam(handle, AACENC_SAMPLERATE, sample_rate);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_SAMPLERATE");

    ret = aacEncoder_SetParam(handle, AACENC_CHANNELMODE, mode);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_CHANNELMODE");

    ret = aacEncoder_SetParam(handle, AACENC_CHANNELORDER, 1);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_CHANNELORDER");

    if (vbr)
    {
        ret = aacEncoder_SetParam(handle, AACENC_BITRATEMODE, vbr);
        MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_BITRATEMODE");
    }
    else
    {
        ret = aacEncoder_SetParam(handle, AACENC_BITRATE, bitrate);
        MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_BITRATE");
    }

    ret = aacEncoder_SetParam(handle, AACENC_TRANSMUX, TT_MP4_ADTS);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_TRANSMUX");

    ret = aacEncoder_SetParam(handle, AACENC_AFTERBURNER, afterburner);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncoder_SetParam AACENC_AFTERBURNER");

    ret = aacEncEncode(handle, NULL, NULL, NULL, NULL);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncEncode");

    ret = aacEncInfo(handle, &info);
    MAZASSERT_RETVAL(ret, -1, "err: aacEncInfo");

    for (i = 0; i < info.confSize; i++)
    {
        dlog(DINF, "conf[%d]        = 0x%02x(h)", i, info.confBuf[i]);
    }

    while(1)        // read files
    {
        AACENC_BufDesc in_buf = { 0 };
        AACENC_BufDesc out_buf = { 0 };
        AACENC_InArgs in_args = { 0 };
        AACENC_OutArgs out_args = { 0 };
        int in_identifier = IN_AUDIO_DATA;
        int in_size;
        int in_elem_size;
        int out_identifier = OUT_BITSTREAM_DATA;
        int out_size;
        int out_elem_size;
        int rcnt;
        int i;
        void *in_ptr;
        void *out_ptr;
        uint8_t inbuf[2048];
        uint8_t outbuf[20480];
        AACENC_ERROR err;

        /* 16bit deepth, 1024 need x2 = 2048 Bytes */
        rcnt = read(ifd, inbuf, 2048);
        if(rcnt == 0)
        {
            break;
        }

        in_ptr = inbuf;
        in_size = rcnt;
        in_elem_size = 2;

        in_args.numInSamples = rcnt <= 0 ? -1 : rcnt / 2;
        in_buf.numBufs = 1;
        in_buf.bufs = &in_ptr;
        in_buf.bufferIdentifiers = &in_identifier;
        in_buf.bufSizes = &in_size;
        in_buf.bufElSizes = &in_elem_size;

        out_ptr = outbuf;
        out_size = sizeof(outbuf);
        out_elem_size = 1;
        out_buf.numBufs = 1;
        out_buf.bufs = &out_ptr;
        out_buf.bufferIdentifiers = &out_identifier;
        out_buf.bufSizes = &out_size;
        out_buf.bufElSizes = &out_elem_size;

        if ((err = aacEncEncode(handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK)
        {
            if (err == AACENC_ENCODE_EOF)
                break;
            fprintf(stderr, "Encoding failed\n");
            return 1;
        }

        if (out_args.numOutBytes == 0)
        {
            printf("%d\r\n", __LINE__);
            continue;
        }

        write(ofd, outbuf, out_args.numOutBytes);
        // printf("%d\n", out_args.numOutBytes);
    }

    aacEncClose(&handle);

    ret = close(ofd);
    MAZASSERT_RETVAL(ret, ret, "err: close fd_aenc ret = %d", ret);

    ret = close(ifd);
    MAZASSERT_RETVAL(ret, ret, "err: close fd ret = %d", ret);

    return 0;
}

